﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using SimpleAppServer.Core;
using System.Net;
using log4net;
using SimpleAppServer.Common;
using System.Threading;
namespace SimpleAppServer.Implement.Socket
{
    /// <summary>
    /// Socket服务器
    /// </summary>
    public  class SocketServer : AbstractAppServer
    {
        /// <summary>
        /// AppSession Cache
        /// </summary>
        Dictionary<SocketAsyncEventArgs, IAppSession> m_SessionCache = new Dictionary<SocketAsyncEventArgs, IAppSession>();

        SocketConfig m_Config = null;
        bool m_Setuped = false;
        /// <summary>
        /// 安装配置
        /// </summary>
        /// <param name="config">SocketConfig</param>
        public override void Setup(IServerConfig config)
        {
            m_Config = config as SocketConfig;
            if (m_Config == null)
            {
                throw new ArgumentException("SocketConfig");
            }
            //Valid Config
            SocketConfigValidator validator = new SocketConfigValidator();
            var result = validator.Validate(m_Config);
            if (!result.IsValid)
            {
                StringBuilder error_message = new StringBuilder();
                foreach (var error in result.Errors)
                {
                    error_message.AppendLine(error.ErrorMessage);
                }
                logger.Error(error_message.ToString());  //log  config errors
            }
            m_Setuped = true;
        }

        bool m_IsRunning = false;
        /// <summary>
        /// 是否运行状态
        /// </summary>
        public override bool IsRunning
        {
            get
            {
                return m_IsRunning;
            }
        }

        /// <summary>
        /// SocketServer
        /// </summary>
        System.Net.Sockets.Socket m_Server = null;

        /// <summary>
        /// BufferManager
        /// </summary>
        BufferManager m_BufferManager = null;

        /// <summary>
        /// SocketAsyncEventArgsPool
        /// </summary>
        SocketAsyncEventArgsPool m_SocketAsyncEventArgsPool = null;

        /// <summary>
        /// 开启服务器
        /// </summary>
        /// <returns>开启成功或失败</returns>
        public override bool Start()
        {
            if (!m_Setuped)
            {
                throw new Exception("尚未调用SteUp安装服务器配置.");
            }
            try
            {
                m_Server = CreateSocket(m_Config.Mode, m_Config.EndPoint);
                if (m_Config.Mode == SocketMode.TCP)
                {
                    m_Server.Listen(5); //Listen队列5，当m_SocketAsyncEventArgsPool.Count=0时，队列当中的客户端Socket虽然Connected，但是并没有被Accept，所以要求客户端需要进行Poll判断是否可读写
                    m_Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);

                    m_BufferManager = new BufferManager(m_Config.MaxSessionCount * m_Config.BuffSize, m_Config.BuffSize);
                    m_BufferManager.Inint();
                    m_SocketAsyncEventArgsPool = new SocketAsyncEventArgsPool(m_Config.MaxSessionCount);
                    for (int i = 0; i < m_Config.MaxSessionCount; i++)
                    {
                        var args = new SocketAsyncEventArgs();
                        args.Completed += new EventHandler<SocketAsyncEventArgs>(TcpServer_Completed);
                        m_SocketAsyncEventArgsPool.Push(args);
                    }
                    if (!ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncTcpCallback),m_Server))
                    {
                        logger.Error("添加Tcp异步Accept线程失败.");
                        return false;
                    }
                }
                else
                {
                    m_BufferManager = new BufferManager(m_Config.MaxSessionCount * m_Config.BuffSize, m_Config.BuffSize);
                    m_BufferManager.Inint();
                    SocketAsyncEventArgs args = new SocketAsyncEventArgs()
                    {
                        RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0)
                    };
                    m_BufferManager.SetBuffer(args);
                    args.UserToken = m_Server;     //Mark ,UserToken
                    args.Completed += new EventHandler<SocketAsyncEventArgs>(UdpServer_Completed);
                    if (!ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncUdpCallback),
                        new SocketAsyncEventArgsToken(m_Server, args)))
                    {
                        logger.Error("添加Udp异步Receive线程失败.");
                        return false;
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex);   
                return false;   //对于服务器Start方法来说，其应用场景需求其只能返回true或false，由任何原因引发的false都应该进行日志记录而不是抛出异常
            }
            m_IsRunning = true;
            logger.Info(string.Format("{0}:SocketServer Started!", DateTime.Now));
            return true;
        }

        /// <summary>
        /// CreateSocket
        /// </summary>
        /// <param name="mode">SocketMode</param>
        /// <param name="endpoint">IPEndPoint</param>
        /// <returns>Socket</returns>
        System.Net.Sockets.Socket CreateSocket(SocketMode mode, IPEndPoint endpoint)
        {
            System.Net.Sockets.Socket sK = null;
            if (mode == SocketMode.TCP)
            {
                sK = new System.Net.Sockets.Socket(endpoint.Address.AddressFamily,   //base on IPEndPoint.Address.AddressFamily
                    SocketType.Stream,
                    ProtocolType.Tcp);
            }
            else
            {
                sK = new System.Net.Sockets.Socket(endpoint.Address.AddressFamily,
                    SocketType.Dgram,
                    ProtocolType.Udp);
            }
            sK.Bind(endpoint);
            return sK;
        }

        /// <summary>
        /// 异步控制
        /// </summary>
        AutoResetEvent m_AsyncCallbackWait = new AutoResetEvent(false);

        #region Udp Server

        /// <summary>
        /// AsyncCallback
        /// </summary>
        /// <param name="args">Object</param>
        void AsyncUdpCallback(object args)
        {
            SocketAsyncEventArgsToken token = (SocketAsyncEventArgsToken)args;
            while (m_IsRunning)
            {
                m_AsyncCallbackWait.Reset();
                try
                {
                    if (!token.Server.ReceiveFromAsync(token.AsyncEventArgs))
                    {
                        UdpReceive(token.AsyncEventArgs);
                    }
                }
                catch (Exception ex)
                {
                    logger.Debug("AsyncUdpCallback", ex);
                }
                m_AsyncCallbackWait.WaitOne();
            }
        }

        /// <summary>
        /// UdpServer SocketAsyncEventArgs.Completed
        /// </summary>
        /// <param name="sender">Sender</param>
        /// <param name="args">SocketAsyncEventArgs</param>
        void UdpServer_Completed(object sender, SocketAsyncEventArgs args)
        {
            if (args.LastOperation == SocketAsyncOperation.ReceiveFrom) 
            {
                UdpReceive(args);
            }
        }

        /// <summary>
        /// 处理异步接收结果
        /// </summary>
        /// <param name="args">SocketAsyncEventArgs</param>
        void UdpReceive(SocketAsyncEventArgs args)
        {
            try
            {
                if (args.SocketError == SocketError.Success)
                {
                    bool receive = true;
                    if (m_Config.ReceiveFilter != null)
                    {
                        receive = m_Config.ReceiveFilter.IsAllow(args.RemoteEndPoint);
                    }
                    if (receive && args.BytesTransferred>0)
                    {
                        byte[] bytes = new byte[args.BytesTransferred];
                        Array.Copy(args.Buffer, args.Offset, bytes, 0, bytes.Length);
                        this.OnReceived(new ReceivedArgs(new UdpSession((System.Net.Sockets.Socket)args.UserToken, args.RemoteEndPoint), bytes));
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Debug("ProcessReceive", ex); 
            }
            finally
            {
                m_AsyncCallbackWait.Set();
            }
        }

        #endregion

        #region Tcp Server

        /// <summary>
        /// AsyncTcpCallback
        /// </summary>
        void AsyncTcpCallback(object args)
        {
            while (m_IsRunning)
            {
                m_AsyncCallbackWait.Reset();
                try
                {
                    if (m_SocketAsyncEventArgsPool.Count > 0)
                    {
                        SocketAsyncEventArgs asyncArgs = m_SocketAsyncEventArgsPool.Pop();
                        asyncArgs.AcceptSocket = null;
                        if (!m_Server.AcceptAsync(asyncArgs))
                        {
                            BeginAccept(asyncArgs);
                        }
                    }
                    else
                    {
                        //有木有办法拒绝Accept捏??? 木有!!!
                        Thread.Sleep(5);
                        continue;
                    }

                    #region 普通异步Accept [调试用]
                    /*
                    m_Server.BeginAccept(new AsyncCallback(iar =>
                    {
                        System.Net.Sockets.Socket sK = (System.Net.Sockets.Socket)iar.AsyncState;
                        try
                        {
                            bool accept=false;
                            while (!accept)
                            {
                                if (m_SocketAsyncEventArgsPool.Count > 0)
                                {
                                    SocketAsyncEventArgs asyncArgs = m_SocketAsyncEventArgsPool.Pop();
                                    asyncArgs.AcceptSocket = sK.EndAccept(iar);
                                    BeginAccept(asyncArgs);  //如果被过滤掉呢？
                                    accept = true;
                                }
                                else
                                {
                                    Thread.Sleep(5);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            logger.Debug("AcceptCallback",ex);
                        }
                        finally
                        {
                            m_AsyncCallbackWait.Set();
                        }
                    }), m_Server);*/

                    #endregion
                }
                catch (Exception ex)
                {
                    logger.Debug("AsyncTcpCallback", ex);
                }
                m_AsyncCallbackWait.WaitOne();
            }
        }


        /// <summary>
        /// Tcp Async Completed
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="args">SocketAsyncEventArgs</param>
        void TcpServer_Completed(object sender,SocketAsyncEventArgs args)
        {
            switch (args.LastOperation)
            {
                case SocketAsyncOperation.Accept:
                    BeginAccept(args);
                    break;
                case SocketAsyncOperation.Receive:
                    BeginReceive(args);
                    break;
            }
        }

        /// <summary>
        /// Begin Accept
        /// </summary>
        /// <param name="args">SocketAsyncEventArgs</param>
        void BeginAccept(SocketAsyncEventArgs args)
        {
            try
            {
                System.Net.Sockets.Socket sK = args.AcceptSocket;
                if (args.SocketError == SocketError.Success)
                {
                    bool regist = true, shutdown = false;
                    if (m_Config.RegistFilter != null)
                    {
                        regist = m_Config.RegistFilter.IsAllow(sK.RemoteEndPoint);
                    }
                    if (regist)   //是否允许注册
                    {
                        if (!m_BufferManager.SetBuffer(args))
                        {
                            shutdown = true;
                            m_SocketAsyncEventArgsPool.Push(args); //注意：别忘记回收SocketAsyncEventArgs
                        }
                    }
                    else
                    {
                        shutdown = true;
                    }
                    if (shutdown) //是否主动关闭
                    {
                        sK.Shutdown(SocketShutdown.Both);
                        sK.Close();
                        sK.Dispose();
                    }
                    else
                    {
                        if (m_Config.KeepLive != null)
                        {
                            //注意：这里使用TCP底层KeepLive，通过IOControl函数完成设置
                            sK.IOControl(IOControlCode.KeepAliveValues, m_Config.KeepLive.GetOptionValues(), null);
                        }
                        if (!sK.ReceiveAsync(args))   //注意：开始Receive
                        {
                            BeginReceive(args);
                        }
                        TcpSession session = new TcpSession(args);
                        session.Released+=new EventHandler(TcpSession_Released);
                        lock (m_SessionCache)
                        {
                            if (!m_SessionCache.ContainsKey(args))
                            {
                                m_SessionCache.Add(args, session);
                                OnRegistSession(new AppSessionArgs(session));   //Registed通知
                            }
                        }
                        
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Debug("BeginAccept",ex);
            }
            finally
            {
                m_AsyncCallbackWait.Set();
            }
        }

        /// <summary>
        /// TcpSession_Released
        /// </summary>
        /// <param name="sender">TcpSession</param>
        /// <param name="args">EventArgs</param>
        void TcpSession_Released(object sender, EventArgs e)
        {
            TcpSession session = (TcpSession)sender;
            SocketAsyncEventArgs args=(SocketAsyncEventArgs)session.UserToken;
            lock (m_SessionCache)
            {
                if (m_SessionCache.ContainsKey(args))
                {
                    m_SessionCache.Remove(args);
                    m_BufferManager.FreeBuffer(args);   //释放并回收SocketAsyncEventArgs
                    m_SocketAsyncEventArgsPool.Push(args); 
                    this.OnUnRegistSession(new AppSessionArgs(session));  //UnRegeisted通知
                }
            }
        }

        /// <summary>
        /// BeginReceive
        /// </summary>
        /// <param name="args">SocketAsyncEventArgs</param>
        void BeginReceive(SocketAsyncEventArgs args)
        {
            IAppSession session = null;
            lock (m_SessionCache)
            {
                if (m_SessionCache.ContainsKey(args))
                {
                    session = m_SessionCache[args];
                }
            }
            if (session == null)   //不存在Session
            {
                return;  
            }
            else
            {
                System.Net.Sockets.Socket sK = args.AcceptSocket;
                if (args.SocketError == SocketError.Success)
                {
                    if (args.BytesTransferred > 0)
                    {
                        byte[] bytes = new byte[args.BytesTransferred];
                        Array.Copy(args.Buffer, args.Offset, bytes, 0, bytes.Length);
                        this.OnReceived(new ReceivedArgs(session, bytes));   //Received通知

                        if (!sK.ReceiveAsync(args))  //不要忘记继续Receive哦
                        {
                            BeginReceive(args);
                        }
                    }
                    else
                    {
                        //如果异步Receive结果BytesTransferred<=0则表明客户端已经断开连接
                        session.Release();
                    }
                }
                else
                {
                    session.Release();  //释放Session,注意是否与KeepLive线程产生并发操作
                }
            }
        }

        #endregion

        /// <summary>
        /// 停止Socket服务器
        /// </summary>
        public override void End()
        {
            try
            {
                m_IsRunning = false;
                m_Server.Shutdown(SocketShutdown.Both);
                m_Server.Close();
                m_Server = null;
            }
            catch (Exception ex)
            {
                logger.Debug(ex);
            }
            finally
            {
                logger.Info(string.Format("{0} SocketServer Ended.", DateTime.Now));
            }
        }

        /// <summary>
        /// GetAllSession
        /// </summary>
        /// <returns>IList</returns>
        public override IList<IAppSession> GetAllSession()
        {
            IList<IAppSession> result = null;
            lock (m_SessionCache)
            {
                result = m_SessionCache.Values.ToList();
            }
            return result;
        }

        /// <summary>
        /// 创建UdpSession
        /// </summary>
        /// <param name="token">EndPoint</param>
        /// <returns>UdpSession</returns>
        public override IAppSession CreateSession(object token=null)
        {
            if (!m_IsRunning)
            {
                throw new NotSupportedException("服务器尚未运行.");
            }
            if (m_Config.Mode != SocketMode.UDP)
            {
                throw new NotSupportedException("CreateSession仅支持UDP方式.");
            }
            if (token == null || (token is EndPoint) == false)
            {
                throw new ArgumentException("SocketServer服务器仅接受EndPoint类型Token.");
            }
            return new UdpSession(m_Server, (EndPoint)token);
        }
    }

    /// <summary>
    /// Token
    /// </summary>
    class SocketAsyncToken
    {
        public SocketAsyncToken(System.Net.Sockets.Socket sK, byte[] buff)
        {
            this.Server = sK;
            this.Buff = buff;
        }

        public System.Net.Sockets.Socket Server
        {
            get;
            private set;
        }

        public byte[] Buff
        {
            get;
            private set;
        }
    }

    /// <summary>
    /// Token
    /// </summary>
    class SocketAsyncEventArgsToken
    {
        public SocketAsyncEventArgsToken(System.Net.Sockets.Socket sK, SocketAsyncEventArgs args)
        {
            this.Server = sK;
            this.AsyncEventArgs = args;
        }

        public System.Net.Sockets.Socket Server
        {
            get;
            private set;
        }

        public SocketAsyncEventArgs AsyncEventArgs
        {
            get;
            private set;
        }
    }
}


/*
struct tcp_keepalive 
{ 
    u_long  onoff; //是否启用Keep-Alive
    u_long  keepalivetime; //多长时间后开始第一次探测（单位：毫秒）
    u_long  keepaliveinterval; //探测时间间隔（单位：毫秒）
}; 
*/